////////////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2003-2006 Adobe Macromedia Software LLC and its licensors.
//  All Rights Reserved. The following is Source Code and is subject to all
//  restrictions on such code as contained in the End User License Agreement
//  accompanying this product.
//
////////////////////////////////////////////////////////////////////////////////

package mx.core
{

import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.events.Event;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextLineMetrics;
import flash.utils.getQualifiedClassName;
import mx.managers.ISystemManager;
import mx.managers.IToolTipManagerClient;
import mx.managers.SystemManager;
import mx.managers.ToolTipManager;
import mx.resources.ResourceBundle;
import mx.styles.ISimpleStyleClient;
import mx.styles.IStyleClient;
import mx.styles.StyleManager;
import mx.styles.StyleProtoChain;

use namespace mx_internal;

include "../styles/metadata/LeadingStyle.as"
include "../styles/metadata/PaddingStyles.as"
include "../styles/metadata/TextStyles.as"

/**
 *  The UITextField class defines the component used by many Flex
 *  components to display text.
 *  For example, the mx.controls.Button control uses a 
 *  UITextField component to define the label area of the Button control. 
 * 
 *  <p>The UITextField class extends the flash.text.TextField class to
 *  support additional functionality required by Flex, such as CSS styles,
 *  invalidation/measurement/layout, enabling/disabling, tooltips, and IME
 *  (Input Method Editor) support for entering Chinese, Japanese, and
 *  Korean text.</p>
 *
 *  @see flash.text.TextField
 *  @see mx.core.UITextFormat
 */
public class UITextField extends FlexTextField
						 implements IIMESupport,
						 IInvalidating, ISimpleStyleClient,
						 IToolTipManagerClient, IUIComponent  
       
{
    include "../core/Version.as";

	//--------------------------------------------------------------------------
	//
	//  Implementation notes
	//
	//--------------------------------------------------------------------------

	/*

		UITextField extends the Player's TextField class,
		so here are some notes about TextField.

		The property values of a new TextField are as follows:

			alwaysShowSelection = false
			autoSize = TextFieldAutoSize.NONE
			background = false
			backgroundColor = 0xFFFFFF
			border = false
			borderColor = 0x000000
			caretIndex = 0
			condenseWhite = false
			displayAsPassword = false
			embedFonts = false
			height = 100
			htmlText = ""
			length = 0
			maxChars = 0
			mouseWheelEnabled = true
			multiline = false
			numLines = 1
			restrict = null
			selectable = true
			selectionBeginIndex = 0
			selectionEndIndex = 0
			text = ""
			textColor = 0x000000
			textHeight = 0
			textWidth = 0
			type = TextFieldType.DYNAMIC
			width = 100
			wordWrap = false
				
		Many of these properties are coupled.
		For example, setting 'text' affects 'htmlText', 'length',
		'textWidth', and 'textHeight'.
		If 'autoSize' isn't "none", it also affects 'width' and 'height'.

		The 'htmlText' getter and setter aren't symmetrical;
		if you set it and then get it, you don't get what you just set;
		you'll get additional HTML markup corresponding to the
		defaultTextFormat.

		If you set both the 'text' and the 'htmlText' properties
		of a TextField, the last one set wins.

		These setters do a lot of work; for example, suppose you set the 'text'.
		If it is an autosizing TextField, it computes the new width and height.
		If it is a wordwrapping TextField, it computes the appropriate line
		breaks.

		If you then get the 'text' property, it is what you just set.
		If you get the 'length', it is the length of the 'text' string.
		If you get the 'htmlText', it will contain a lot of autogenerated
		HTML markup corresponding to the defaultTextFormat, which was applied
		as a run across the entire new text.

		Now suppose you set the 'htmlText' property.
		The Player parses the string, separating the text characters
		from the markup.
		It first applies the defaultTextFormat as a run across the entire new
		text; it then uses the markup to modify this TextFormat or create
		additional TextFormat runs.
		When it's done it discards the 'htmlText' string that you set.
		
		If you then get the 'htmlText', it will not be what you just set; it
		will contain additional HTML markup corresponding to defaultTextFormat
		If you get the 'text', it will be text characters in the 'htmlText',
		without any of the HTML markup.
		If you get the 'length', it is the length of the 'text' string.

		If you set a TextFormat run with setTextFormat(), it will change the
		runs created from the HTML markup in the 'htmlText' that was last set.
		This is why, in the validateNow() method in UITextField, the original
		'htmlText' is reapplied after the TextFormat is changed.
	
		The 'condenseWhite' property only applies when setting 'htmlText',
		not 'text'.
		Changing 'condenseWhite' after setting 'htmlText' doesn't affect
		anything except future settings of 'htmlText'.
		
		The width and height of the TextField are 4 pixels greater than
		the textWidth and textHeight.
	
	*/

	//--------------------------------------------------------------------------
	//
	//  Class initialization
	//
	//--------------------------------------------------------------------------

	loadResources();

	//--------------------------------------------------------------------------
	//
	//  Class resources
	//
	//--------------------------------------------------------------------------

	[ResourceBundle("core")]
	
    /**
	 *  @private
     */	
	private static var packageResources:ResourceBundle;
	
    /**
	 *  @private
     */	
	private static var resourceTruncationIndicator:String;

    /**
	 *  @private
	 *  The padding to be added to textWidth to get the width
	 *  of a TextField that can display the text without clipping.
     */	
	mx_internal static const TEXT_WIDTH_PADDING:int = 5;

    /**
	 *  @private
	 *  The padding to be added to textHeight to get the height
	 *  of a TextField that can display the text without clipping.
     */	
	mx_internal static const TEXT_HEIGHT_PADDING:int = 4;

	//--------------------------------------------------------------------------
	//
	//  Class methods
	//
	//--------------------------------------------------------------------------

    /**
	 *  @private    
     *  Loads resources for this class.
     */
	private static function loadResources():void
	{
		resourceTruncationIndicator =
			packageResources.getString("truncationIndicator");
	}
	
    //--------------------------------------------------------------------------
    //
    //  Constructor
    //
    //--------------------------------------------------------------------------

    /**
     *  Constructor.
     */
    public function UITextField()
    {
        super();

		focusRect = false;
        selectable = false;
        tabEnabled = false;

		addEventListener(Event.CHANGE, changeHandler);
		addEventListener("textFieldStyleChange", textFieldStyleChangeHandler);
	}

    //--------------------------------------------------------------------------
    //
    //  Variables
    //
    //--------------------------------------------------------------------------

    /**
     *  @private
     *  Cached value of the TextFormat read from the Styles.
     */
    private var cachedTextFormat:TextFormat;

    /**
     *  @private
     */
    private var invalidateDisplayListFlag:Boolean = true;

    /**
     *  @private
     */
    mx_internal var styleChangedFlag:Boolean = true;

	/**
	 *  @private
	 *  This var is either the last value of 'htmlText' that was set
	 *  or null (if 'text' was set instead of 'htmlText').
	 *
	 *  This var is different from getting the 'htmlText',
	 *  because when you set 'htmlText' into a TextField and then get it,
	 *  you don't get what you set; what you get includes additional
	 *  HTML markup generated from the defaultTextFormat
	 *  (which for a Flex component is based on the CSS styles).
	 *
	 *  When you set 'htmlText', a TextField parses through it
	 *  and creates TextFormat runs based on the HTML markup.
	 *  It applies these on top of the defaultTextFormat.
	 *  A TextField saves the non-markup characters as the 'text',
	 *  but it doesn't save the original 'htmlText',
	 *  so we have to do this ourselves.
	 *
	 *  If the CSS styles change, validateNow() will get called
	 *  and a new TextFormat based on the new CSS styles
	 *  will get applied to the entire TextField, wiping
	 *  out any TextFormats that came from the HTML markup.
	 *  So we use this var to re-apply the original markup
	 *  after a CSS change.
	 */
	private var explicitHTMLText:String = null;

    /**
     *  @private
     *  Color set explicitly by setColor(); overrides style lookup.
     */
    mx_internal var explicitColor:uint = StyleManager.NOT_A_COLOR;

    //--------------------------------------------------------------------------
    //
    //  Overridden properties
    //
    //--------------------------------------------------------------------------
    
    //----------------------------------
    //  htmlText
    //----------------------------------

    /**
     *  @private
     */
    override public function set htmlText(value:String):void
    {
        // TextField's htmlText property can't be set to null.
        if (!value)
            value = "";

    	// Performance optimization: if the htmlText hasn't changed,
		// don't let the player think that we're dirty.
		if (isHTML && super.htmlText == value)
			return;

		// Reapply the format because TextField would otherwise reset to
		// black, Times New Roman, 12
		if (cachedTextFormat)
			defaultTextFormat = cachedTextFormat;
			
		super.htmlText = value;

		// Remember the htmlText that we've set,
		// because the TextField doesn't remember it for us.
		// We need it so that we can re-apply the HTML markup
		// in validateNow() after the CSS styles change
		explicitHTMLText = value;

		if (invalidateDisplayListFlag)
			validateNow();
    }

    //----------------------------------
    //  parent
    //----------------------------------

    /**
     *  @private
     *  Reference to this component's virtual parent container.
	 *  "Virtual" means that this parent may not be the same
	 *  as the one that the Player returns as the 'parent'
	 *  property of a DisplayObject.
	 *  For example, if a Container has created a contentPane
	 *  to improve scrolling performance,
	 *  then its "children" are really its grandchildren
	 *  and their "parent" is actually their grandparent,
	 *  because we don't want developers to be concerned with
	 *  whether a contentPane exists or not.
     */
    mx_internal var _parent:DisplayObjectContainer;

    /**
     *  The parent container or component for this component.
     */
    override public function get parent():DisplayObjectContainer
    {
        // Flash PlaceObject tags can have super.parent set
		// before we get to setting the _parent property.
        return _parent ? _parent : super.parent;
    }

    //----------------------------------
    //  text
    //----------------------------------

    /**
     *  @private
     */
    override public function set text(value:String):void
    {
        // TextField's text property can't be set to null.
        if (!value)
            value = "";
		
		// Performance optimization: if the text hasn't changed,
		// don't let the player think that we're dirty.
		if (!isHTML && super.text == value)
			return;

		super.text = value;

		explicitHTMLText = null;

		if (invalidateDisplayListFlag)
			validateNow();
    }

    //--------------------------------------------------------------------------
    //
    //  Properties
    //
    //--------------------------------------------------------------------------
    
    //----------------------------------
    //  baselinePosition
    //----------------------------------

    /**
     *  Determines the baseline y-coordinate
	 *  of the first line of text of the component.
	 *  Any subclass of UITextField should override this property.
     */
    public function get baselinePosition():Number
    {
        var tlm:TextLineMetrics = getLineMetrics(0);
		return height - 4 - tlm.descent;
    }
	
    //----------------------------------
    //  className
    //----------------------------------

    /**
     *  The name of this instance's class, such as
	 *  <code>"DataGridItemRenderer"</code>.
	 *
	 *  <p>This string does not include the package name.
	 *  If you need the package name as well, call the
	 *  <code>getQualifiedClassName()</code> method in the flash.utils package.
	 *  It will return a string such as
	 *  <code>"mx.controls.dataGridClasses::DataGridItemRenderer"</code>.</p>
     */
    public function get className():String
    {
		var name:String = getQualifiedClassName(this);
		
		// If there is a package name, strip it off.
		var index:int = name.indexOf("::");
		if (index != -1)
			name = name.substr(index + 2);
				
		return name;
    }

    //----------------------------------
    //  document
    //----------------------------------

    /**
     *  @private
     *  Storage for the enabled property.
     */
    private var _document:Object;

    /**
     *  A reference to the document object associated with this UITextField object. 
     *  A document object is an Object at the top of the hierarchy of a Flex application, 
     *  MXML component, or AS component.
     */
    public function get document():Object
    {
        return _document;
    }

    /**
     *  @private
     */
    public function set document(value:Object):void
    {
        _document = value;
    }

    //----------------------------------
    //  enabled
    //----------------------------------

    /**
     *  @private
     *  Storage for the enabled property.
     */
    private var _enabled:Boolean = true;

    /**
     *  A Boolean value that indicates whether the component is enabled. 
	 *  This property only affects
	 *  the color of the text and not whether the UITextField is editable.
	 *  To control editability, use the 
	 *  <code>flash.text.TextField.type</code> property.
	 *  
	 *  @default true
	 *  @see flash.text.TextField
     */
    public function get enabled():Boolean
    {
        return _enabled;
    }

    /**
     *  @private
     */
    public function set enabled(value:Boolean):void
    {
        mouseEnabled = value;
        _enabled = value;

        styleChanged("color");
    }

    //----------------------------------
    //  explicitHeight
    //----------------------------------

    /**
     *  @private
	 *  Storage for the explicitHeight property.
     */
	private var _explicitHeight:Number;

	/**
     *  @copy mx.core.UIComponent#explicitHeight
	 */
	public function get explicitHeight():Number
	{
		return _explicitHeight;
	}

    /**
     *  @private
     */
    public function set explicitHeight(value:Number):void
    {
        _explicitHeight = value;
	}

    //----------------------------------
    //  explicitMaxHeight
    //----------------------------------

	/**
     *  Number that specifies the maximum height of the component, 
     *  in pixels, in the component's coordinates. 
     *
     *  <p>This value is used by the container in calculating the size 
     *  and position of the component. 
     *  It is not used by the component itself in determining its default size. 
     *  Thus this property may not have any effect if parented by Container, 
     *  or containers that don't factor in this property. 
     *  Because the value is in component coordinates, the true <code>maxHeight</code> 
     *  with respect to its parent is affected by the <code>scaleY</code> property.</p>
	 *  
	 *  @default NaN
	 */
	public function get explicitMaxHeight():Number
	{
		return NaN;
	}

    //----------------------------------
    //  explicitMaxWidth
    //----------------------------------

	/**
     *  Number that specifies the maximum width of the component, 
     *  in pixels, in the component's coordinates. 
     *
     *  <p>This value is used by the container in calculating the size 
     *  and position of the component. 
     *  It is not used by the component itself in determining its default size. 
     *  Thus this property may not have any effect if parented by Container, 
     *  or containers that don't factor in this property. 
     *  Because the value is in component coordinates, the true <code>maxWidth</code> 
     *  with respect to its parent is affected by the <code>scaleX</code> property.</p>
	 *  
	 *  @default NaN
	 */
	public function get explicitMaxWidth():Number
	{
		return NaN;
	}

    //----------------------------------
    //  explicitMinHeight
    //----------------------------------

	/**
     *  @copy mx.core.UIComponent#explicitMinHeight
	 */
	public function get explicitMinHeight():Number
	{
		return NaN;
	}

    //----------------------------------
    //  explicitMinWidth
    //----------------------------------

	/**
     *  @copy mx.core.UIComponent#explicitMinWidth
	 */
	public function get explicitMinWidth():Number
	{
		return NaN;
	}

    //----------------------------------
    //  explicitWidth
    //----------------------------------

    /**
     *  @private
	 *  Storage for the explicitWidth property.
     */
	private var _explicitWidth:Number;

	/**
     *  @copy mx.core.UIComponent#explicitWidth
	 */
	public function get explicitWidth():Number
	{
		return _explicitWidth;
	}

    /**
     *  @private
     */
    public function set explicitWidth(value:Number):void
    {
        _explicitWidth = value;
	}

    //----------------------------------
    //  focusPane
    //----------------------------------

	/**
	 *  @inheritDoc
     */
    public function get focusPane():Sprite
	{
		return null;
	}

	/**
     *  @private
     */
    public function set focusPane(value:Sprite):void
    {
    }

    //----------------------------------
    //  ignorePadding
    //----------------------------------

    /**
     *  @private
     *  Storage for the ignorePadding property.
     */
    private var _ignorePadding:Boolean = true;

    /**
     *  If <code>true</code>, the <code>paddingLeft</code> and
	 *  <code>paddingRight</code> styles will not add space
	 *  around the text of the component.
     *  
	 *  @default true
     */
    public function get ignorePadding():Boolean
    {
        return _ignorePadding;
    }

    /**
     *  @private
     */
    public function set ignorePadding(value:Boolean):void
    {
        _ignorePadding = value;

        styleChanged(null);
    }

    //----------------------------------
    //  imeMode
    //----------------------------------

    /**
     *  @private
	 *  Storage for the imeMode property.
     */
    private var _imeMode:String = null;

    /**
     *  Specifies the IME (input method editor) mode.
     *  The IME enables users to enter text in Chinese, Japanese, and Korean.
     *  Flex sets the specified IME mode when the control gets the focus,
     *  and sets it back to the previous value when the control loses the focus.
     *
     * <p>The flash.system.IMEConversionMode class defines constants for the
	 *  valid values for this property.
     *  You can also specify <code>null</code> to specify no IME.</p>
     *
     *  @see flash.system.IMEConversionMode
     *
	 *  @default null
     */
    public function get imeMode():String
    {
        return _imeMode;
    }

    /**
     *  @private
     */
    public function set imeMode(value:String):void
    {
        _imeMode = value;
    }

    //----------------------------------
    //  includeInLayout
    //----------------------------------

	/**
	 *  @private
	 *  Storage for the includeInLayout property.
	 */
	private var _includeInLayout:Boolean = true;

	/**
     *  @copy mx.core.UIComponent#includeInLayout
	 */
	public function get includeInLayout():Boolean
	{
		return _includeInLayout;
	}

	/**
	 *  @private
	 */
	public function set includeInLayout(value:Boolean):void
	{
		if (_includeInLayout != value)
		{
			_includeInLayout = value;

			var p:IInvalidating = parent as IInvalidating;
			if (p)
			{
				p.invalidateSize();
				p.invalidateDisplayList();
			}
		}
	}

    //----------------------------------
    //  inheritingStyles
    //----------------------------------

    /**
     *  @private
	 *  Storage for the inheritingStyles property.
     */
    private var _inheritingStyles:Object = UIComponent.STYLE_UNINITIALIZED;

    /**
     *  The beginning of this UITextField's chain of inheriting styles.
	 *  The <code>getStyle()</code> method accesses
	 *  <code>inheritingStyles[styleName]</code> to search the entire
	 *  prototype-linked chain.
	 *  This object is set up by the <code>initProtoChain()</code> method.
	 *  You typically never need to access this property directly.
     */
    public function get inheritingStyles():Object
	{
		return _inheritingStyles;
	}

    /**
     *  @private
	 */
    public function set inheritingStyles(value:Object):void
	{
		_inheritingStyles = value;
	}

	//----------------------------------
	//  initialized
	//----------------------------------

    /**
     *  @private
	 *  Storage for the initialize property.
     */
	private var _initialized:Boolean = false;

    /**
	 *  A flag that determines if an object has been through all three phases
	 *  of layout validation (provided that any were required)
     */
    public function get initialized():Boolean
	{
		return _initialized;
	}

    /**
     *  @private
     */
    public function set initialized(value:Boolean):void
	{
		_initialized = value;
	}

    //----------------------------------
	//  isHTML
    //----------------------------------

	/**
	 *  @private
	 */
	private function get isHTML():Boolean
	{
		return explicitHTMLText != null;
	}

    //----------------------------------
    //  maxHeight
    //----------------------------------

	/**
     *  @copy mx.core.UIComponent#maxHeight
	 */
	public function get maxHeight():Number
	{
		return UIComponent.DEFAULT_MAX_HEIGHT;
	}

    //----------------------------------
    //  maxWidth
    //----------------------------------

	/**
     *  @copy mx.core.UIComponent#maxWidth
	 */
	public function get maxWidth():Number
	{
		return UIComponent.DEFAULT_MAX_WIDTH;
	}

    //----------------------------------
    //  measuredHeight
    //----------------------------------

    /**
     *  @copy mx.core.UIComponent#measuredHeight
     */
    public function get measuredHeight():Number
    {
        validateNow();
        return textHeight + TEXT_HEIGHT_PADDING;
    }

    //----------------------------------
    //  measuredMinHeight
    //----------------------------------

	/**
     *  @copy mx.core.UIComponent#measuredMinHeight
	 */
	public function get measuredMinHeight():Number
	{
		return 0;
	}

	/**
	 *  @private
	 */
	public function set measuredMinHeight(value:Number):void
	{
	}

    //----------------------------------
    //  measuredMinWidth
    //----------------------------------

	/**
     *  @copy mx.core.UIComponent#measuredMinWidth
	 */
	public function get measuredMinWidth():Number
	{
		return 0;
	}

	/**
	 *  @private
	 */
	public function set measuredMinWidth(value:Number):void
	{
	}

    //----------------------------------
    //  measuredWidth
    //----------------------------------

    /**
     *  @copy mx.core.UIComponent#measuredWidth
     */
    public function get measuredWidth():Number
    {
        validateNow();
        return textWidth + TEXT_WIDTH_PADDING;
    }

    //----------------------------------
    //  minHeight
    //----------------------------------

	/**
     *  @copy mx.core.UIComponent#minHeight
	 */
	public function get minHeight():Number
	{
		return 0;
	}

    //----------------------------------
    //  minWidth
    //----------------------------------

	/**
     *  @copy mx.core.UIComponent#minWidth
	 */
	public function get minWidth():Number
	{
		return 0;
	}

    //----------------------------------
    //  nestLevel
    //----------------------------------

    /**
     *  @private
     *  Storage for the nestLevel property.
     */
	private var _nestLevel:int = 0;

    /**
     *  @copy mx.core.UIComponent#nestLevel
     */
	public function get nestLevel():int
	{
		return _nestLevel;
	}
	
    /**
     *  @private
     */
	public function set nestLevel(value:int):void
	{
		// If my parent hasn't been attached to the display list, then its nestLevel
		// will be zero.  If it tries to set my nestLevel to 1, ignore it.  We'll
		// update nest levels again after the parent is added to the display list.
		//
		// Also punt if the new value for nestLevel is the same as my current value.
		if (value > 1 && _nestLevel != value)
		{
			_nestLevel = value;

			StyleProtoChain.initTextField(this);
			styleChangedFlag = true;
			validateNow();
		}
	}
	
    //----------------------------------
    //  nonInheritingStyles
    //----------------------------------

    /**
	 *  @private
	 *  Storage for the nonInheritingStyles property.
	 */
	private var _nonInheritingStyles:Object = UIComponent.STYLE_UNINITIALIZED;

    /**
     *  The beginning of this UITextField's chain of non-inheriting styles.
	 *  The <code>getStyle()</code> method accesses
	 *  <code>nonInheritingStyles[styleName]</code> method to search the entire
	 *  prototype-linked chain.
	 *  This object is set up by the <code>initProtoChain()</code> method.
	 *  You typically never need to access this property directly.
     */
    public function get nonInheritingStyles():Object
	{
		return _nonInheritingStyles;
	}

    /**
     *  @private
	 */
    public function set nonInheritingStyles(value:Object):void
	{
		_nonInheritingStyles = value;
	}

    //----------------------------------
    //  percentHeight
    //----------------------------------

	/**
     *  @copy mx.core.UIComponent#percentHeight
	 */
	public function get percentHeight():Number
	{
		return NaN;
	}

	/**
	 *  @private
	 */
	 public function set percentHeight(value:Number):void
	 {
	 }

    //----------------------------------
    //  percentWidth
    //----------------------------------

	/**
     *  @copy mx.core.UIComponent#percentWidth
	 */
	public function get percentWidth():Number
	{
		return NaN;
	}

	/**
	 *  @private
	 */
	 public function set percentWidth(value:Number):void
	 {
	 }

	//----------------------------------
	//  processedDescriptors
	//----------------------------------

    /**
     *  @private
     */
	private var _processedDescriptors:Boolean = true;

    /**
     *  Set to <code>true</code> after the <code>createChildren()</code>
     *  method creates any internal component children.
     */
    public function get processedDescriptors():Boolean
	{
		return _processedDescriptors;
	}

    /**
     *  @private
     */
    public function set processedDescriptors(value:Boolean):void
	{
		_processedDescriptors = value;
	}

    //----------------------------------
    //  styleName
    //----------------------------------

    /**
     *  @private
     *  Storage for the styleName property.
     */
    private var _styleName:Object /* String, CSSStyleDeclaration, or UIComponent */;

    /**
     *  @copy mx.core.UIComponent#styleName
     */
    public function get styleName():Object /* String, CSSStyleDeclaration, or UIComponent */
    {
        return _styleName;
    }

    /**
     *  @private
     */
    public function set styleName(value:Object /* String, CSSStyleDeclaration, or UIComponent */):void
    {
        if (_styleName === value)
            return;

        _styleName = value;

        if (parent)
        {
            StyleProtoChain.initTextField(this);
            styleChanged("styleName");
        }

        // If we don't have a parent pointer yet, then we'll wait
		// and initialize the proto chain when the parentChanged()
		// method is called.
    }

 	//----------------------------------
	//  systemManager
	//----------------------------------

	/**
     *  @copy mx.core.UIComponent#systemManager
	 */
	public function get systemManager():ISystemManager
	{
		var o:DisplayObject = parent;
		while (o)
		{
			var ui:IUIComponent = o as IUIComponent;
			if (ui)
				return ui.systemManager;

			o = o.parent;
		}

		return null;
	}

	/**
	 *  @private
	 */
	public function set systemManager(value:ISystemManager):void
	{
		// Not supported
	}

 	//----------------------------------
	//  toolTip
	//----------------------------------

	/**
	 *  @private
	 *  Storage for the toolTip property.
	 */
	private var _toolTip:String;

	/**
     *  @copy mx.core.UIComponent#toolTip
	 */
	public function get toolTip():String
	{
		return _toolTip;
	}

	/**
	 *  @private
	 */
	public function set toolTip(value:String):void
	{
		ToolTipManager.registerToolTip(this, value);

		_toolTip = value;
	}

   //----------------------------------
    //  tweeningProperties
    //----------------------------------

	/**
     *  @copy mx.core.UIComponent#tweeningProperties
	 */
	public function get tweeningProperties():Array
	{
		return null;
	}

	/**
	 *  @private
	 */
	public function set tweeningProperties(value:Array):void
	{
	}

	//----------------------------------
	//  updateCompletePendingFlag
	//----------------------------------

    /**
     *  @private
	 *  Storage for the updateCompletePendingFlag property.
     */
	private var _updateCompletePendingFlag:Boolean = false;

    /**
	 *  A flag that determines if an object has been through all three phases
	 *  of layout validation (provided that any were required)
     */
    public function get updateCompletePendingFlag():Boolean
	{
		return _updateCompletePendingFlag;
	}

    /**
     *  @private
     */
    public function set updateCompletePendingFlag(value:Boolean):void
	{
		_updateCompletePendingFlag = value;
	}

    //--------------------------------------------------------------------------
    //
    //  Overridden methods: TextField
    //
    //--------------------------------------------------------------------------

	/**
	 *  @private
	 */
	override public function setTextFormat(format:TextFormat,
										   beginIndex:int = -1,
										   endIndex:int = -1):void
	{
		super.setTextFormat(format, beginIndex, endIndex);

		// Since changing the TextFormat will change the htmlText,
		// dispatch an event so that listeners can react to this.
		dispatchEvent(new Event("textFormatChange"));
	}	
	
	//--------------------------------------------------------------------------
    //
    //  Methods
    //
    //--------------------------------------------------------------------------

	/**
	 *  Initializes this component.
	 *
	 *  <p>This method is required by the IUIComponent interface,
	 *  but it actually does nothing for a UITextField.</p>
	 */
	public function initialize():void
	{
	}

    /**
     *  @copy mx.core.UIComponent#getExplicitOrMeasuredWidth()
     */
    public function getExplicitOrMeasuredWidth():Number
    {
		return !isNaN(explicitWidth) ? explicitWidth : measuredWidth;
    }

    /**
     *  @copy mx.core.UIComponent#getExplicitOrMeasuredHeight()
     */
    public function getExplicitOrMeasuredHeight():Number
    {
		return !isNaN(explicitHeight) ? explicitHeight : measuredHeight;
    }

	/**
	 *  Sets the <code>visible</code> property of this UITextField object.
	 * 
	 *  @param visible <code>true</code> to make this UITextField visible, 
	 *  and <code>false</code> to make it invisible.
	 *
	 *  @param noEvent <code>true</code> to suppress generating an event when you change visibility.
	 */
	public function setVisible(visible:Boolean, noEvent:Boolean = false):void
	{
		this.visible = visible
	}

	/**
     *  @copy mx.core.UIComponent#setFocus()
	 */
	public function setFocus():void
	{
		systemManager.stage.focus = this;
	}

    /**
	 *  Returns a UITextFormat object that contains formatting information for this component. 
	 *  This method is similar to the <code>getTextFormat()</code> method of the 
	 *  flash.text.TextField class, but it returns a UITextFormat object instead 
	 *  of a TextFormat object.
     *
	 *  <p>The UITextFormat class extends the TextFormat class to add the text measurement methods
	 *  <code>measureText()</code> and <code>measureHTMLText()</code>.</p>
	 *
	 *  @return An object that contains formatting information for this component.
	 *
	 *  @see mx.core.UITextFormat
	 *  @see flash.text.TextField
	 */
	public function getUITextFormat():UITextFormat
	{
		validateNow();
		
		var textFormat:UITextFormat = new UITextFormat(systemManager);
		
		textFormat.copyFrom(getTextFormat());
		
		textFormat.antiAliasType = antiAliasType;
		textFormat.gridFitType = gridFitType;
		textFormat.sharpness = sharpness;
		textFormat.thickness = thickness;
		
		return textFormat;
	}

	/**
     *  @copy mx.core.UIComponent#move()
     */
    public function move(x:Number, y:Number):void
    {
    	// Performance optimization: if the position hasn't changed, don't let
    	// the player think that we're dirty
    	if (this.x != x)
    	    this.x = x;
		if (this.y != y)    	   
	        this.y = y;
    }

    /**
     *  @copy mx.core.UIComponent#setActualSize()
     */
    public function setActualSize(w:Number, h:Number):void
    {
    	// Performance optimization: if the size hasn't changed, don't let
    	// the player think that we're dirty
    	if (width != w)
        	width = w;
        if (height != h)
        	height = h;
    }

    /**
     *  @copy mx.core.UIComponent#getStyle()
     */
    public function getStyle(styleProp:String):*
    {
        if (StyleManager.inheritingStyles[styleProp])
		{        
        	return inheritingStyles ?
				   inheritingStyles[styleProp] :
				   IStyleClient(parent).getStyle(styleProp);
		}
		else
		{		
        	return nonInheritingStyles ?
				   nonInheritingStyles[styleProp] :
				   IStyleClient(parent).getStyle(styleProp);
		}   
    }

    /**
     *  Does nothing.
	 *  A UITextField cannot have inline styles.
     *
     *  @param styleProp Name of the style property.
     *
     *  @param newValue New value for the style.
     */
    public function setStyle(styleProp:String, value:*):void
    {
    }

    /**
     *  This function is called when a UITextField object is assigned
     *  a parent.
	 *  You typically never need to call this method.
	 *
	 *  @param p The parent of this UITextField object.
     */
    public function parentChanged(p:DisplayObjectContainer):void
    {
        if (!p)
        {
            _parent = null;
            _nestLevel = 0;
        }
        else if (p is IStyleClient)
        {
            _parent = p;
        }
        else if (p is SystemManager)
        {
            _parent = p;
        }
        else
        {
            _parent = p.parent;
        }
    }

    /**
     *  @copy mx.core.UIComponent#styleChanged()
     */
    public function styleChanged(styleProp:String):void
    {
    	styleChangedFlag = true;

        if (!invalidateDisplayListFlag)
        {
            invalidateDisplayListFlag = true;
			UIComponent(parent).callLater(validateNow);
        }
    }

    /**
     *  @copy mx.core.UIComponent#validateNow()
     */
    public function validateNow():void
    {
        // If we don't have a parent pointer yet, then any attempts to get
        // style information will fail.  Do nothing now - this function will
        // be called again when parentChanged is called.
        if (!parent)
            return;

		if (!isNaN(explicitWidth) && super.width != explicitWidth)
			super.width = (explicitWidth > 4) ? explicitWidth : 4;

		if (!isNaN(explicitHeight) && super.height != explicitHeight)
			super.height = explicitHeight;

          // Set the text format.
		if (styleChangedFlag)
        {
            var textFormat:TextFormat = getTextStyles();
			
			embedFonts = textFormat.font ?
						 systemManager != null &&
						 systemManager.isFontFaceEmbedded(textFormat) :
						 getStyle("embedFonts");

			antiAliasType = getStyle("fontAntiAliasType");
			gridFitType = getStyle("fontGridFitType");
			sharpness = getStyle("fontSharpness");
			thickness = getStyle("fontThickness");

			super.setTextFormat(textFormat);
            defaultTextFormat = textFormat;
					
			// Since changing the TextFormat will change the htmlText,
			// dispatch an event so that listeners can react to this.
			dispatchEvent(new Event("textFieldStyleChange"));
        }
        
        styleChangedFlag = false;
        invalidateDisplayListFlag = false;
    }

    /**
     *  Returns the TextFormat object that represents 
     *  character formatting information for this UITextField object.
     *
     *  @return A TextFormat object. 
     *
     *  @see flash.text.TextFormat
     */
    public function getTextStyles():TextFormat
    {
        var textFormat:TextFormat = new TextFormat();

        textFormat.align = getStyle("textAlign");
        textFormat.bold = getStyle("fontWeight") == "bold";
		if (enabled)
        {
            if (explicitColor == StyleManager.NOT_A_COLOR)
                textFormat.color = getStyle("color");
            else
                textFormat.color = explicitColor;
        }
        else
        {
            textFormat.color = getStyle("disabledColor");
        }
        textFormat.font = getStyle("fontFamily");
        textFormat.indent = getStyle("textIndent");
        textFormat.italic = getStyle("fontStyle") == "italic";
        textFormat.leading = getStyle("leading");
        textFormat.leftMargin = ignorePadding ? 0 : getStyle("paddingLeft");
        textFormat.rightMargin = ignorePadding ? 0 : getStyle("paddingRight");
        textFormat.size = getStyle("fontSize");
        textFormat.underline = getStyle("textDecoration") == "underline";

		cachedTextFormat = textFormat;
        return textFormat;
    }

    /**
     *  Sets the font color of the text.
     *
     *  @param color The new font color.
     */
    public function setColor(color:uint):void
    {
        explicitColor = color;
        styleChangedFlag = true;
		invalidateDisplayListFlag = true;
        
		validateNow();
    }

    /**
     *  @copy mx.core.UIComponent#invalidateSize()
     */
    public function invalidateSize():void
    {
        invalidateDisplayListFlag = true;
    }

    /**
     *  @copy mx.core.UIComponent#invalidateDisplayList()
     */
    public function invalidateDisplayList():void
    {
        invalidateDisplayListFlag = true;
    }

    /**
     *  @copy mx.core.UIComponent#invalidateProperties()
     */
	public function invalidateProperties():void
	{
	}
	
    /**
     *  Truncate text to make it fit horizontally in the area defined for the control, 
     *  and append an ellipsis, three periods (...), to the text.
     *
     *  @param truncationIndicator The text to be appended after truncation.
	 *  If you pass <code>null</code>, a localizable string
	 *  such as <code>"..."</code> will be used.
     *
     *  @return <code>true</code> if the text needed truncation.
     */
    public function truncateToFit(truncationIndicator:String = null):Boolean
    {
		if (!truncationIndicator)
			truncationIndicator = resourceTruncationIndicator;
		
		// Ensure that the proper CSS styles get applied to the textField
		// before measuring text.
		// Otherwise the callLater(validateNow) in styleChanged()
		// can apply the CSS styles too late.
		validateNow();

		var originalText:String = super.text;

		var w:Number = width;

        if (originalText != "" && textWidth + TEXT_WIDTH_PADDING > w)
        {
            // This should get us into the ballpark.
			var s:String = super.text = originalText;
				originalText.slice(0,
					Math.floor((w / (textWidth + TEXT_WIDTH_PADDING)) * originalText.length));

            while (s.length > 1 && textWidth + TEXT_WIDTH_PADDING > w)
            {
				s = s.slice(0, -1);
				super.text = s + truncationIndicator;
            }
			
			return true;
        }

        return false;
    }

    //--------------------------------------------------------------------------
    //
    //  Event handlers
    //
    //--------------------------------------------------------------------------

	/**
	 *  @private
	 */
	private function changeHandler(event:Event):void
	{
		// If the user changes the text displayed by the TextField,
		// whatever htmlText might have been set is now irrelevant.
		// This means that we can no longer re-apply any HTML markup
		// after a CSS style change.
		explicitHTMLText = null;
	}

	/**
	 *  @private
	 */
	private function textFieldStyleChangeHandler(event:Event):void
	{
		// Some TextFormat in the TextField just changed.
		// If the TextField is displaying htmlText we need
		// to reset the htmlText that was last set
		// so that its markup is applied on top of the new TextFormat.
		if (explicitHTMLText != null)
			super.htmlText = explicitHTMLText;
	}

    //--------------------------------------------------------------------------
    //
    //  IUIComponent
    //
    //--------------------------------------------------------------------------

    /**
     *  Returns <code>true</code> if the child is parented or owned by this object.
     *
     *  @param child The child DisplayObject.
     *
     *  @return <code>true</code> if the child is parented or owned by this UITextField object.
     * 
	 *  @see #owner
     */
    public function owns(child:DisplayObject):Boolean
    {
		return child == this;
	}

    //----------------------------------
    //  owner
    //----------------------------------

    /**
     *  @private
     */
    private var _owner:DisplayObjectContainer;

    /**
	 *  By default, set to the parent container of this object. 
	 *  However, if this object is a child component that is 
	 *  popped up by its parent, such as the dropdown list of a ComboBox control, 
	 *  the owner is the component that popped up this object. 
	 *
	 *  <p>This property is not managed by Flex, but by each component. 
	 *  Therefore, if you use the <code>PopUpManger.createPopUp()</code> or 
	 *  <code>PopUpManger.addPopUp()</code> method to pop up a child component, 
	 *  you should set the <code>owner</code> property of the child component 
	 *  to the component that popped it up.</p>
	 * 
	 *  <p>The default value is the value of the <code>parent</code> property.</p>
     */
    public function get owner():DisplayObjectContainer
    {
        return _owner ? _owner : parent;
    }

    public function set owner(value:DisplayObjectContainer):void
    {
        _owner = value;
    }

}

}
